<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        #container{
            text-align: center;
        }
        #content{
            width: 640px;
            margin: auto;
            position: relative;
        }
        #canvas{
            position: absolute;
        }
        input{
            vertical-align: center;
        }
    </style>
</head>

<body>

   <div id="container">
       <h1>弹幕</h1>
       <div id="content">
           <canvas id="canvas"></canvas>
           <video id="video" src="./video/白蛇缘起.mp4" width="640" height="380" controls></video>
       </div>
       <input type="text" id="text">
       <button id="add">添加弹幕</button>
       <input type="color" id="color">
       <input type="range" id="range" max="40" min="10">
   </div>

<script type="text/javascript">

    let data = [
        //值、速度、出现时间
        {value:'珠峰架构师公开课',speed:2,time:0,color:'red',fontSize:20} ,
        {value:'小帅哥',time:1}
    ];

    let $ = document.querySelector.bind(document);
    let canvas = $('#canvas');
    let video = $('#video');

    class CanvasBarrage{
        constructor(canvas, video, options = {}){  //构造函数
            if(!canvas || !video){
                return;
            }
            this.canvas = canvas;
            this.video = video;
            let defaultOptions = {  //默认选项  弹幕的默认值
                fontSize: 20,
                color: 'gold',
                speed: 2,
                opacity: 0.3,    //透明度
                data: []
            };

            // Object.assign(defaultOptions,options);  //把options 属性套给 defaultOptions
            //对象的合并，方便
            Object.assign(this,defaultOptions,options); //把这些对象属性，全部拷贝、挂载在这个实例上
            console.log(this);

            //获取canvas画布
            this.context = canvas.getContext('2d');
            //设置canvas和video等大
            this.canvas.width = this.video.clientWidth;
            this.canvas.height = this.video.clientHeight;

            //是否暂停
            this.isPaused = true;   //默认暂停播放，表示不渲染弹幕
            //存放所有弹幕,Barrage是创造弹幕的实例的类
            this.barrages = this.data.map(obj => new Barrage(obj, this));
            console.log(this.barrages);
            //渲染所有弹幕
            this.render();

        };

        //渲染弹幕
        render(){
            //第一次 先进行晴空操作，执行渲染弹幕，如果没有暂停，继续渲染
            this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);    //从哪开始到哪，清理
            this.renderBarrage();   //渲染弹幕
            if(this.isPaused == false){
                //递归渲染
                requestAnimationFrame(this.render.bind(this));

            }
        }

        //将数组的弹幕一个一个输出，判断时间和视频的时间是否符合，符合就执行渲染
        renderBarrage(){

            let time = this.video.currentTime;
            this.barrages.forEach(barrage => {
                if(!barrage.flag && time >= barrage.time){
                    //先去初始化，初始化后在进行绘制
                    //1、如果没哟u 初始化，先去初始化一下
                    if(!barrage.isInited){
                        barrage.init();
                        barrage.isInited = true;
                    }
                    barrage.x -= barrage.speed;
                    barrage.render();   //渲染自己
                    if(barrage.x <= barrage.width * -1){
                        barrage.flag = true;    //做停止渲染标记
                    }
                }
            });

        };

        add(obj){
            this.barrages.push(new Barrage(obj, this));
        };

        reset(){
            this.context.clearRect(0, 0 ,this.canvas.width, this.canvas.height);
            let time = this.video.currentTime;
            this.barrages.forEach(barrage => {
                barrage.flag = false;
                if(time <= barrage.time){
                    barrage.isInited = false;   //重新初始化
                }else{
                    barrage.flag = true;    //其他弹幕不再渲染
                }
            })
        }

    }

    class Barrage{
        constructor(obj, ctx) {
            this.value = obj.value; //弹幕内容
            this.time = obj.time;  //弹幕时间
            this.obj = obj;
            this.ctx = ctx;
        };

        //算弹幕位置大小宽度
        init(){
            this.opacity = this.obj.opacity || this.ctx.opacity;
            this.color = this.obj.color ||  this.ctx.color;
            this.fontSize = this.obj.fontSize || this.ctx.fontSize;
            this.speed = this.obj.speed || this.ctx.speed;

            //求自己的宽度，目的是用来校验当前是否还需要继续绘制
            let span = document.createElement('span');
            span.innerText = this.value;
            span.style.font = this.fontSize + 'px "Microsoft YaHei"';
            span.style.position = 'absolute';
            document.body.appendChild(span);
            //记录弹幕有多宽
            this.width = span.clientWidth;
            document.body.removeChild(span);
            //弹幕的出现位置
            this.x = this.ctx.canvas.width;
            this.y = this.ctx.canvas.height * Math.random();

            if(this.y < this.fontSize){
                this.y = this.fontSize;
            }
            if(this.y > this.ctx.canvas.height - this.fontSize){
                this.y = this.ctx.canvas.height - this.fontSize;
            }

        };

        //渲染自己，将自己画在画布上
        render(){

            this.ctx.context.font = this.fontSize + 'px "Microsoft YaHei"';
            this.ctx.context.fillStyle = this.color;
            this.ctx.context.fillText(this.value, this.x, this.y);

        };

    }

    let canvasBarrage = new CanvasBarrage(canvas, video, {
        data
    });

    video.addEventListener('play',function () {
        canvasBarrage.isPaused = false;
        canvasBarrage.render();
    });

    video.addEventListener('pause', function () {
        canvasBarrage.isPaused = true;
    })

    $('#add').addEventListener('click', function () {
        let value = $('#text').value;
        let time = video.currentTime;
        let color = $('#color').value;
        let fontSize = $('#range').value;
        let obj = {time, value, color, fontSize};
        canvasBarrage.add(obj);    //添加弹幕，实现添加功能
    });
    
    video.addEventListener('seeked', function () {
        canvasBarrage.reset();
    })
    

</script>

</body>

</html>